package com.zhang.autotouch.service;

import android.annotation.SuppressLint;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaRecorder;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Binder;
import android.os.Build;
import android.os.Environment;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.RequiresApi;

import com.zhang.autotouch.R;
import com.zhang.autotouch.bean.AutoEvent;
import com.zhang.autotouch.bean.ScreenInfo;
import com.zhang.autotouch.bean.SearchPoint;
import com.zhang.autotouch.utils.FileUtils;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.opencv.android.Utils;
import org.opencv.calib3d.Calib3d;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.DMatch;
import org.opencv.core.KeyPoint;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfDMatch;
import org.opencv.core.MatOfKeyPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.features2d.DescriptorMatcher;
import org.opencv.features2d.Features2d;
import org.opencv.features2d.SIFT;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import static android.os.Build.VERSION_CODES.O;
import static org.opencv.core.CvType.CV_8UC1;

public class ScreenRecordService extends Service {

    private static final String TAG = "ScreenRecordService";

    public int data;

    private int mScreenWidth;
    private int mScreenHeight;
    private int mScreenDensity;
    private int mResultCode;
    private Intent mResultData;
    /** 是否为标清视频 */
    private boolean isVideoSd;
    /** 是否开启音频录制 */
    private boolean isAudio;

    private ImageReader mImageReader;
    private MediaProjection mMediaProjection;
    private MediaRecorder mMediaRecorder;
    private VirtualDisplay mVirtualDisplay;
    private VirtualDisplay mImageDisplay;

    Mat matTemp;

    // 后台线程
    private Callback callback;
    Timer timer = new Timer();
    TimerTask timerTask = new TimerTask() {
        @SuppressLint("NewApi")
        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        @Override
        public void run() {
            if(callback != null){
                Bitmap bm = getBitmap();
                if(bm != null) {
                    Mat src =new Mat();
                    Utils.bitmapToMat(bm, src);

                    // 模糊匹配
                    Mat a = new Mat();
                    Mat b = new Mat();
                    Imgproc.cvtColor(src, a, Imgproc.COLOR_BGR2GRAY);
                    Imgproc.cvtColor(matTemp, b, Imgproc.COLOR_BGR2GRAY);
                    matchImage(b, a);

                    // 写入原生Bitmap
                    Utils.matToBitmap(a, bm);

                    callback.onBitmapChange(bm);
                }
            }
        }
    };

    public SearchPoint searchImg(Bitmap tag){
        Mat m = new Mat();
        Utils.bitmapToMat(tag, m);
        return searchImg(m);
    }

    /**
     * 搜索指定的图片
     * @param tag
     * @return null不存在
     */
    public SearchPoint searchImg(Mat tag){
        Bitmap bm = getBitmap();
        if(bm != null) {
            Mat src =new Mat();
            Utils.bitmapToMat(bm, src);

            // 模糊匹配
            Mat a = new Mat();
            Mat b = new Mat();
            Imgproc.cvtColor(src, a, Imgproc.COLOR_BGR2GRAY);
            Imgproc.cvtColor(tag, b, Imgproc.COLOR_BGR2GRAY);
            return searchImg(b, a);
        }
        return null;
    }

    /**
     * 图片调试使用
     * @param name
     * @param pic
     */
    public void printPic(String name, Mat pic){
        Bitmap temp = Bitmap.createBitmap(pic.cols(), pic.rows(), Bitmap.Config.ARGB_8888);
        if(pic.type() == 5){
            Imgcodecs.imwrite(FileUtils.getSavePath() + name + "-5.png", pic);
            Mat dis = new Mat();
            pic.convertTo(dis, CV_8UC1, 255, 0);
            Utils.matToBitmap(dis, temp);
        } else {
            Utils.matToBitmap(pic, temp);
        }

        FileUtils.saveImage(temp, name);
        temp.recycle();
    }

    /**
     * 模糊匹配
     * @param templateImage 目标
     * @param originalImage 原始图片
     * @return
     */
    @RequiresApi(api = Build.VERSION_CODES.N)
    public SearchPoint searchImg(Mat templateImage, Mat originalImage) {
        Mat resT = new Mat();
        Mat resO = new Mat();

        //即当detector 又当Detector
        SIFT sift = SIFT.create();

        MatOfKeyPoint templateKeyPoints = new MatOfKeyPoint();
        MatOfKeyPoint originalKeyPoints = new MatOfKeyPoint();

        System.out.println("寻找最佳匹配");

        //获取模板图的特征点
        sift.detect(templateImage, templateKeyPoints);
        sift.detect(originalImage, originalKeyPoints);

        sift.compute(templateImage, templateKeyPoints, resT);
        sift.compute(originalImage, originalKeyPoints, resO);

        List<MatOfDMatch> matches = new LinkedList();
        DescriptorMatcher descriptorMatcher = DescriptorMatcher.create(DescriptorMatcher.FLANNBASED);

        printPic("1-目标图片", templateImage);
        printPic("1-截图图片", originalImage);

        printPic("2-目标图片(特征点)", resT);
        printPic("2-截图图片(特征点)", resO);

        float nndrRatio = 0.65f;
        /**
         * knnMatch方法的作用就是在给定特征描述集合中寻找最佳匹配
         * 使用KNN-matching算法，令K=2，则每个match得到两个最接近的descriptor，然后计算最接近距离和次接近距离之间的比值，当比值大于既定值时，才作为最终match。
         */
        descriptorMatcher.knnMatch(resT, resO, matches, 2);
        System.out.println("计算匹配结果");
        LinkedList<DMatch> goodMatchesList = new LinkedList();
        //对匹配结果进行筛选，依据distance进行筛选
        matches.forEach(match -> {
            DMatch[] dmatcharray = match.toArray();
            DMatch m1 = dmatcharray[0];
            DMatch m2 = dmatcharray[1];

            if (m1.distance <= m2.distance * nndrRatio) {
                goodMatchesList.addLast(m1);
            }
        });

        int matchesPointCount = goodMatchesList.size();
        //当匹配后的特征点大于等于 4 个，则认为模板图在原图中，该值可以自行调整
        if (matchesPointCount >= 4) {
            System.out.println("模板图在原图匹配成功！");

            List<KeyPoint> templateKeyPointList = templateKeyPoints.toList();
            List<KeyPoint> originalKeyPointList = originalKeyPoints.toList();
            LinkedList<Point> objectPoints = new LinkedList();
            LinkedList<Point> scenePoints = new LinkedList();
            goodMatchesList.forEach(goodMatch -> {
                objectPoints.addLast(templateKeyPointList.get(goodMatch.queryIdx).pt);
                scenePoints.addLast(originalKeyPointList.get(goodMatch.trainIdx).pt);
            });
            MatOfPoint2f objMatOfPoint2f = new MatOfPoint2f();
            objMatOfPoint2f.fromList(objectPoints);
            MatOfPoint2f scnMatOfPoint2f = new MatOfPoint2f();
            scnMatOfPoint2f.fromList(scenePoints);
            //使用 findHomography 寻找匹配上的关键点的变换
            Mat homography = Calib3d.findHomography(objMatOfPoint2f, scnMatOfPoint2f, Calib3d.RANSAC, 3);

            /**
             * 透视变换(Perspective Transformation)是将图片投影到一个新的视平面(Viewing Plane)，也称作投影映射(Projective Mapping)。
             */
            Mat templateCorners = new Mat(4, 1, CvType.CV_32FC2);
            Mat templateTransformResult = new Mat(4, 1, CvType.CV_32FC2);
            templateCorners.put(0, 0, new double[]{0, 0});
            templateCorners.put(1, 0, new double[]{templateImage.cols(), 0});
            templateCorners.put(2, 0, new double[]{templateImage.cols(), templateImage.rows()});
            templateCorners.put(3, 0, new double[]{0, templateImage.rows()});
            //使用 perspectiveTransform 将模板图进行透视变以矫正图象得到标准图片
            Core.perspectiveTransform(templateCorners, templateTransformResult, homography);

            //矩形四个顶点  匹配的图片经过旋转之后就这个矩形的四个点的位置就不是正常的abcd了
            double[] pointA = templateTransformResult.get(0, 0);
            double[] pointB = templateTransformResult.get(1, 0);
            double[] pointC = templateTransformResult.get(2, 0);
            double[] pointD = templateTransformResult.get(3, 0);

            // 调试信息
            Imgproc.rectangle(originalImage, new Point(pointA), new Point(pointC), new Scalar(0, 255, 0));
            MatOfDMatch goodMatches = new MatOfDMatch();
            goodMatches.fromList(goodMatchesList);
            Mat matchOutput = new Mat(originalImage.rows() * 2, originalImage.cols() * 2, Imgcodecs.IMREAD_COLOR);
            Features2d.drawMatches(templateImage, templateKeyPoints, originalImage, originalKeyPoints, goodMatches, matchOutput, new Scalar(0, 255, 0), new Scalar(255, 0, 0), new MatOfByte(), 2);
            Features2d.drawMatches(templateImage, templateKeyPoints, originalImage, originalKeyPoints, goodMatches, matchOutput, new Scalar(0, 255, 0), new Scalar(255, 0, 0), new MatOfByte(), 2);

            printPic("3-查找后的图片（匹配）", matchOutput);
            printPic("3-查找后的图片", originalImage);
            // end 调试信息

            return new SearchPoint(pointA, pointB, pointC, pointD);

            //将匹配的图像用用四条线框出来
            //Imgproc.rectangle(originalImage, new Point(pointA), new Point(pointC), new Scalar(0, 255, 0));

            //System.out.println("寻找到的坐标点 A "+new Point(pointA).toString()+" B "+new Point(pointB).toString());
        } else {
            System.out.println("模板图不在原图中！");
            return null;
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    public void matchImage(Mat templateImage, Mat originalImage) {
        Mat resT = new Mat();
        Mat resO = new Mat();

        //即当detector 又当Detector
        SIFT sift = SIFT.create();

        MatOfKeyPoint templateKeyPoints = new MatOfKeyPoint();
        MatOfKeyPoint originalKeyPoints = new MatOfKeyPoint();

        System.out.println("寻找最佳匹配");

        //获取模板图的特征点
        sift.detect(templateImage, templateKeyPoints);
        sift.detect(originalImage, originalKeyPoints);

        sift.compute(templateImage, templateKeyPoints, resT);
        sift.compute(originalImage, originalKeyPoints, resO);

        List<MatOfDMatch> matches = new LinkedList();
        DescriptorMatcher descriptorMatcher = DescriptorMatcher.create(DescriptorMatcher.FLANNBASED);

        float nndrRatio = 1.0f/1.5f;
        /**
         * knnMatch方法的作用就是在给定特征描述集合中寻找最佳匹配
         * 使用KNN-matching算法，令K=2，则每个match得到两个最接近的descriptor，然后计算最接近距离和次接近距离之间的比值，当比值大于既定值时，才作为最终match。
         */
        descriptorMatcher.knnMatch(resT, resO, matches, 2);
        System.out.println("计算匹配结果");
        LinkedList<DMatch> goodMatchesList = new LinkedList();
        //对匹配结果进行筛选，依据distance进行筛选
        matches.forEach(match -> {
            DMatch[] dmatcharray = match.toArray();
            DMatch m1 = dmatcharray[0];
            DMatch m2 = dmatcharray[1];

            if (m1.distance <= m2.distance * nndrRatio) {
                goodMatchesList.addLast(m1);
            }
        });

        int matchesPointCount = goodMatchesList.size();
        //当匹配后的特征点大于等于 4 个，则认为模板图在原图中，该值可以自行调整
        if (matchesPointCount >= 4) {
            System.out.println("模板图在原图匹配成功！");

            List<KeyPoint> templateKeyPointList = templateKeyPoints.toList();
            List<KeyPoint> originalKeyPointList = originalKeyPoints.toList();
            LinkedList<Point> objectPoints = new LinkedList();
            LinkedList<Point> scenePoints = new LinkedList();
            goodMatchesList.forEach(goodMatch -> {
                objectPoints.addLast(templateKeyPointList.get(goodMatch.queryIdx).pt);
                scenePoints.addLast(originalKeyPointList.get(goodMatch.trainIdx).pt);
            });
            MatOfPoint2f objMatOfPoint2f = new MatOfPoint2f();
            objMatOfPoint2f.fromList(objectPoints);
            MatOfPoint2f scnMatOfPoint2f = new MatOfPoint2f();
            scnMatOfPoint2f.fromList(scenePoints);
            //使用 findHomography 寻找匹配上的关键点的变换
            Mat homography = Calib3d.findHomography(objMatOfPoint2f, scnMatOfPoint2f, Calib3d.RANSAC, 3);

            /**
             * 透视变换(Perspective Transformation)是将图片投影到一个新的视平面(Viewing Plane)，也称作投影映射(Projective Mapping)。
             */
            Mat templateCorners = new Mat(4, 1, CvType.CV_32FC2);
            Mat templateTransformResult = new Mat(4, 1, CvType.CV_32FC2);
            templateCorners.put(0, 0, new double[]{0, 0});
            templateCorners.put(1, 0, new double[]{templateImage.cols(), 0});
            templateCorners.put(2, 0, new double[]{templateImage.cols(), templateImage.rows()});
            templateCorners.put(3, 0, new double[]{0, templateImage.rows()});
            //使用 perspectiveTransform 将模板图进行透视变以矫正图象得到标准图片
            Core.perspectiveTransform(templateCorners, templateTransformResult, homography);

            //矩形四个顶点  匹配的图片经过旋转之后就这个矩形的四个点的位置就不是正常的abcd了
            double[] pointA = templateTransformResult.get(0, 0);
            double[] pointB = templateTransformResult.get(1, 0);
            double[] pointC = templateTransformResult.get(2, 0);
            double[] pointD = templateTransformResult.get(3, 0);

            //指定取得数组子集的范围
//            int rowStart = (int) pointA[1];
//            int rowEnd = (int) pointC[1];
//            int colStart = (int) pointD[0];
//            int colEnd = (int) pointB[0];
            //rowStart, rowEnd, colStart, colEnd 好像必须左上右下  没必要从原图扣下来模板图了
//            Mat subMat = originalImage.submat(rowStart, rowEnd, colStart, colEnd);
//            printPic("yppt", subMat);

            //将匹配的图像用用四条线框出来
            Imgproc.rectangle(originalImage, new Point(pointA), new Point(pointC), new Scalar(0, 255, 0));

            System.out.println("寻找到的坐标点 A "+new Point(pointA).toString()+" B "+new Point(pointB).toString());

           /* Core.line(originalImage, new Point(pointA), new Point(pointB), new Scalar(0, 255, 0), 4);//上 A->B
            Core.line(originalImage, new Point(pointB), new Point(pointC), new Scalar(0, 255, 0), 4);//右 B->C
            Core.line(originalImage, new Point(pointC), new Point(pointD), new Scalar(0, 255, 0), 4);//下 C->D
            Core.line(originalImage, new Point(pointD), new Point(pointA), new Scalar(0, 255, 0), 4);//左 D->A*/

//            printPic("ppgc", matchOutput);
//            printPic("ytwz", originalImage);
        } else {
            System.out.println("模板图不在原图中！");
        }
    }

    public ScreenRecordService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();

//        Bitmap temp = BitmapFactory.decodeResource(getResources(), R.drawable.template);
//        matTemp = new Mat();
//        Utils.bitmapToMat(temp, matTemp);
//        temp.recycle();

        Log.i(TAG, "onCreate is called");
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
//        Log.i(TAG, "onStartCommand is called");
//
//        mResultCode = intent.getIntExtra("code", -1);
//        mResultData = intent.getParcelableExtra("data");
//        mScreenWidth = intent.getIntExtra("width", 720);
//        mScreenHeight = intent.getIntExtra("height", 1280);
//        mScreenDensity = intent.getIntExtra("density", 1);
//        isVideoSd = intent.getBooleanExtra("quality", true);
//        isAudio = intent.getBooleanExtra("audio", true);
//
//        mMediaProjection =  createMediaProjection();
//        mMediaRecorder = createMediaRecorder();
//        initImageReader();
//        mVirtualDisplay = createVirtualDisplay(); // 必须在mediaRecorder.prepare() 之后调用，否则报错"fail to get surface"
//        mImageDisplay = createImageDisplay();
//        mMediaRecorder.start();
//
//        return Service.START_NOT_STICKY;
    }

    /**
     * 初始化ImageRead参数
     */
    @SuppressLint("WrongConstant")
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    public void initImageReader() {
        if (mImageReader != null) {
            mImageReader.close();
            mImageReader = null;
        }
        mImageReader = ImageReader.newInstance(mScreenWidth, mScreenHeight, PixelFormat.RGBA_8888, 2);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private MediaProjection createMediaProjection() {
        Log.i(TAG, "Create MediaProjection");
        return ((MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE)).getMediaProjection(mResultCode, mResultData);
    }

    /**
     * 获取一个保存屏幕录像的路径
     * @return path
     */
    public String getSavePath() {
        if (Environment.getExternalStorageState()
                .equals(Environment.MEDIA_MOUNTED)) {
            String rootDir = Environment.getExternalStorageDirectory()
                    .getAbsolutePath() + "/" +
                    "ScreenRecord" + "/";

            File file = new File(rootDir);
            if (!file.exists()) {
                if (!file.mkdirs()) {
                    return null;
                }
            }
            return rootDir;
        } else {
            return null;
        }
    }

    /**
     * 请求完权限后马上获取有可能为null，可以通过判断is null来重复获取。
     */
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    public Bitmap getBitmap() {
        Bitmap bitmap = cutoutFrame();
        if (bitmap == null) {
            getBitmap();
        }

        FileUtils.saveImage(bitmap, "原始图片");

        return bitmap;
    }

    /**
     * 通过底层来获取下一帧的图像
     *
     * @return bitmap
     */
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    public Bitmap cutoutFrame() {
        Image image = mImageReader.acquireLatestImage();
        if (image == null) {
            return null;
        }
        int width = image.getWidth();
        int height = image.getHeight();
        final Image.Plane[] planes = image.getPlanes();
        final ByteBuffer buffer = planes[0].getBuffer();
        int pixelStride = planes[0].getPixelStride();
        int rowStride = planes[0].getRowStride();
        int rowPadding = rowStride - pixelStride * width;
        Bitmap bitmap = Bitmap.createBitmap(width +
                rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
        bitmap.copyPixelsFromBuffer(buffer);
        image.close();
        return Bitmap.createBitmap(bitmap, 0, 0, width, height);
    }


    private MediaRecorder createMediaRecorder() {

        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
        Date curDate = new Date(System.currentTimeMillis());
        String curTime = formatter.format(curDate).replace(" ", "");
        String videoQuality = "HD";
        if(isVideoSd) videoQuality = "SD";

        Log.i(TAG, "Create MediaRecorder");
        MediaRecorder mediaRecorder = new MediaRecorder();
        if(isAudio) mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        mediaRecorder.setOutputFile(getSavePath() + videoQuality + curTime + ".mp4");
        mediaRecorder.setVideoSize(mScreenWidth, mScreenHeight);  //after setVideoSource(), setOutFormat()
        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);  //after setOutputFormat()
        if(isAudio) mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);  //after setOutputFormat()
        int bitRate;
        if(isVideoSd) {
            mediaRecorder.setVideoEncodingBitRate(mScreenWidth * mScreenHeight);
            mediaRecorder.setVideoFrameRate(30);
            bitRate = mScreenWidth * mScreenHeight / 1000;
        } else {
            mediaRecorder.setVideoEncodingBitRate(5 * mScreenWidth * mScreenHeight);
            mediaRecorder.setVideoFrameRate(60); //after setVideoSource(), setOutFormat()
            bitRate = 5 * mScreenWidth * mScreenHeight / 1000;
        }
        try {
            mediaRecorder.prepare();
        } catch (IllegalStateException | IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Log.i(TAG, "Audio: " + isAudio + ", SD video: " + isVideoSd + ", BitRate: " + bitRate + "kbps");

        return mediaRecorder;
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private VirtualDisplay createVirtualDisplay() {
        Log.i(TAG, "Create VirtualDisplay");
        return mMediaProjection.createVirtualDisplay(TAG, mScreenWidth, mScreenHeight, mScreenDensity,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mMediaRecorder.getSurface(), null, null);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private VirtualDisplay createImageDisplay() {
        Log.i(TAG, "Create VirtualDisplay");
        return mMediaProjection.createVirtualDisplay(TAG, mScreenWidth, mScreenHeight, mScreenDensity,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mImageReader.getSurface(), null, null);
    }

    public class MyBinder extends Binder{
        public ScreenRecordService getService(){
            return ScreenRecordService.this;
        }

        void TransferData(int mData){
            data = mData;
        }

        int getData(){
            return data;
        }
    }

    public void setCallback(Callback callback) {
        this.callback = callback;
    }

    public Callback getCallback() {
        return callback;
    }

    public interface Callback {
        void onBitmapChange(Bitmap data);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.

        Log.i(TAG, "onBind is called");

        mResultCode = intent.getIntExtra("code", -1);
        mResultData = intent.getParcelableExtra("data");
        mScreenWidth = intent.getIntExtra("width", 720);
        mScreenHeight = intent.getIntExtra("height", 1280);
        mScreenDensity = intent.getIntExtra("density", 1);
        isVideoSd = intent.getBooleanExtra("quality", true);
        isAudio = intent.getBooleanExtra("audio", false);

        mMediaProjection =  createMediaProjection();
        //mMediaRecorder = createMediaRecorder();
        initImageReader();
        //mVirtualDisplay = createVirtualDisplay(); // 必须在mediaRecorder.prepare() 之后调用，否则报错"fail to get surface"
        mImageDisplay = createImageDisplay();
        //mMediaRecorder.start();

        //timer.schedule(timerTask, 0, 5000);
        Log.i(TAG, "Screen Record Binder");

        // 绑定事件
        EventBus.getDefault().register(this);

        return new MyBinder();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onReciverEvent(ScreenInfo si){
        mScreenWidth = si.getScreenWidth();
        mScreenHeight = si.getScreenHeight();
        mScreenDensity = si.getScreenDensity();

        if(mMediaProjection!=null){
            mMediaProjection.stop();
            mMediaProjection = null;
        }
        mMediaProjection =  createMediaProjection();
        initImageReader();
        if(mImageDisplay != null){
            mImageDisplay.release();
            mImageDisplay = null;
        }
        mImageDisplay = createImageDisplay();
        Log.i(TAG, "发生横屏竖屏切换，更新截图服务，"+si);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        timer.cancel();
        Log.i(TAG, "Service onDestroy");
        if(mVirtualDisplay != null) {
            mVirtualDisplay.release();
            mVirtualDisplay = null;
        }
        if(mImageDisplay != null) {
            mImageDisplay.release();
            mImageDisplay = null;
        }
        if(mMediaRecorder != null) {
            mMediaRecorder.setOnErrorListener(null);
            mMediaProjection.stop();
            mMediaRecorder.reset();
        }
        if(mMediaProjection != null) {
            mMediaProjection.stop();
            mMediaProjection = null;
        }
    }

}